package com.javaxiaobear.base.common.utils;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.TemporalAccessorUtil;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.map.SafeConcurrentHashMap;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.javaxiaobear.base.common.exception.ServiceException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentMap;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import reactor.util.function.Tuple2;
import reactor.util.function.Tuples;

/**
 * 日期工具类
 *
 * @author LarryYan
 * @date 2018/6/22 15:32
 */
public final class Dates extends DateUtil {

  public static final String CTS_DATE_FORMAT = "EEE MMM dd HH:mm:ss z yyyy";

  public static final String DATE_FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSZ";

  public static final String DATE_FORMAT_ISO8601_LITE = "yyyy-MM-dd'T'HH:mm:ss.SSS";

  public static final String DATE_FORMAT_ISO8601_SHORT = "yyyy-MM-dd'T'HH:mm:ss";

  public static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";

  public static final String DATETIME_SHORT_MILL_FORMAT = "yyyy-MM-dd HH:mm:ss.S";

  public static final String DATETIME_PLUS_FORMAT = "yyyy-MM-dd+HH:mm:ss";

  public static final String DATETIME_MILL_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

  public static final String DATETIME_SIMPLE_FORMAT = "yyyyMMddHHmmss";

  public static final String DATETIME_SIMPLE_SHORT_FORMAT = "yyMMddHHmmss";

  public static final String DATE_FORMAT = "yyyy-MM-dd";

  public static final String DATE_SIMPLE_FORMAT = "yyyyMMdd";

  public static final String DATE_SIMPLE_SHORT_FORMAT = "yyMMdd";

  public static final String DATE_UNDERLINE_FORMAT = "yyyy_MM_dd";

  public static final String TIME_FORMAT = "HH:mm:ss";

  public static final String TIME_PLUS_FORMAT = "HH:mm:ss.SSS";

  public static final String TIME_SIMPLE_FORMAT = "HHmmss";

  public static final String DEFAULT_FORMAT = DATETIME_FORMAT;

  public static final String DEFAULT_DATETIME_FORMAT = DATETIME_FORMAT;

  public static final String DEFAULT_DATE_FORMAT = DATE_FORMAT;

  public static final String DEFAULT_TIME_FORMAT = TIME_FORMAT;

  public static final List<String> DEFAULT_FORMATS =
      ListUtil.toList(
          DATETIME_FORMAT,
          DATE_FORMAT,
          TIME_FORMAT,
          DATE_SIMPLE_FORMAT,
          TIME_SIMPLE_FORMAT,
          DATETIME_MILL_FORMAT,
          DATETIME_PLUS_FORMAT,
          DATE_UNDERLINE_FORMAT,
          DATE_SIMPLE_SHORT_FORMAT,
          DATETIME_SIMPLE_SHORT_FORMAT,
          DATETIME_SIMPLE_FORMAT,
          DATE_FORMAT_ISO8601,
          DATE_FORMAT_ISO8601_LITE,
          CTS_DATE_FORMAT,
          DATETIME_SHORT_MILL_FORMAT);

  public static final Locale DEFAULT_LOCALE = Locale.getDefault();

  public static final TimeZone DEFAULT_TIMEZONE = TimeZone.getDefault();

  public static final ZoneOffset DEFAULT_ZONE_OFF_SET = ZoneOffset.ofHours(8);

  private static final ConcurrentMap<Tuple2<String, Locale>, DateTimeFormatter>
      DATE_TIME_FORMATTER_CACHE = new SafeConcurrentHashMap<>(7);

  public static String[] getDefaultFormats() {
    return DEFAULT_FORMATS.toArray(new String[0]);
  }

  /** 指定时间是否在当前时间之后 */
  public static boolean isAfterNow(Date date) {
    return Objects.requireNonNull(date).after(new Date());
  }

  /** 指定时间是否在当前时间之后 */
  public static boolean isAfterNow(LocalDateTime localDateTime) {
    return Objects.requireNonNull(localDateTime).isAfter(LocalDateTime.now());
  }

  /** 指定时间是否在当前时间之后 */
  public static boolean isAfterNow(LocalDate localDate) {
    return Objects.requireNonNull(localDate).isAfter(LocalDate.now());
  }

  /** 指定时间是否在当前时间之后 */
  public static boolean isAfterNow(LocalTime time) {
    return Objects.requireNonNull(time).isAfter(LocalTime.now());
  }

  /** 指定时间是否在当前时间之前 */
  public static boolean isBeforeNow(Date date) {
    return Objects.requireNonNull(date).after(new Date());
  }

  /** 指定时间是否在当前时间之前 */
  public static boolean isBeforeNow(LocalDateTime localDateTime) {
    return Objects.requireNonNull(localDateTime).isBefore(LocalDateTime.now());
  }

  /** 指定时间是否在当前时间之前 */
  public static boolean isBeforeNow(LocalDate localDate) {
    return Objects.requireNonNull(localDate).isBefore(LocalDate.now());
  }

  /** 指定时间是否在当前时间之前 */
  public static boolean isBeforeNow(LocalTime localTime) {
    return Objects.requireNonNull(localTime).isBefore(LocalTime.now());
  }

  /** 当前时间戳 */
  public static long currentTimeMillis() {
    return DateUtil.current();
  }

  /** 当前时间戳 */
  public static long currentTimeSeconds() {
    return DateUtil.currentSeconds();
  }

  /** 是否是同一天 */
  public static boolean isSameDay(Date date1, Date date2) {
    if (date1 == null || date2 == null) {
      throw new IllegalArgumentException("日期不能为空");
    }
    LocalDate localDate1 = toLocalDate(date1);
    LocalDate localDate2 = toLocalDate(date2);
    return localDate1.isEqual(localDate2);
  }

  public static Stream<LocalDate> rangeDay(LocalDate startDate, LocalDate endDate) {
    var diffDays = diffDays(startDate, endDate);

    Stream.Builder<LocalDate> builder = Stream.builder();
    for (int i = 0; i < diffDays + 1; i++) {
      builder.accept(startDate.plusDays(i));
    }
    return builder.build();
  }

  public static Stream<LocalDate> rangeDay(Date startDate, Date endDate) {
    return rangeDay(toLocalDate(startDate), toLocalDate(endDate));
  }

  /** 将String格式的日期转成另一种String格式 */
  public static String convert(String dateStr, String oldPattern, String newPattern) {
    if (StrUtil.isEmpty(dateStr)) {
      return null;
    }
    return format(parse(dateStr, oldPattern), newPattern);
  }

  /** 日期格式化 */
  public static String format(Date date, String format) {
    if (date == null) {
      return null;
    }
    return new DateTime(date).toString(format);
  }

  /** 日期格式化，默认格式 */
  public static String format(Date date) {
    return format(date, DEFAULT_FORMAT);
  }

  public static String formatDate(Date date) {
    return format(date, DATE_FORMAT);
  }

  public static String formatTime(Date date) {
    return format(date, TIME_FORMAT);
  }

  /** 日期格式化 */
  public static String format(LocalDate date, String format) {
    if (date == null) {
      return null;
    }
    try {
      return date.format(formatter(format));
    } catch (RuntimeException e) {
      throw new ServiceException(date + ",日期格式不正确:" + format);
    }
  }

  /** 日期格式化，默认格式 */
  public static String format(LocalDate date) {
    return format(date, DATE_FORMAT);
  }

  /** 日期格式化 */
  public static String format(LocalDateTime date, String format) {
    if (date == null) {
      return null;
    }
    return date.format(formatter(format));
  }

  /** 日期格式化，默认格式 */
  public static String format(LocalTime time) {
    return format(time, TIME_FORMAT);
  }

  /** 日期格式化 */
  public static String format(LocalTime time, String format) {
    if (time == null) {
      return null;
    }
    return time.format(formatter(format));
  }

  /** 日期格式化，默认格式 */
  public static String format(LocalDateTime date) {
    return format(date, DEFAULT_FORMAT);
  }

  /** 转Date */
  public static Date toDate(LocalDateTime localDateTime) {
    if (localDateTime == null) {
      return null;
    }
    return DateTime.of(toEpochMilli(localDateTime));
  }

  public static long toEpochMilli(TemporalAccessor temporalAccessor) {
    return LocalDateTimeUtil.toEpochMilli(temporalAccessor);
  }

  public static Instant toInstant(TemporalAccessor temporalAccessor) {
    return TemporalAccessorUtil.toInstant(temporalAccessor);
  }

  public static Date toDate(LocalDate temporalAccessor) {
    if (temporalAccessor == null) {
      return null;
    }
    return DateTime.from(toInstant(temporalAccessor));
  }

  /** 转Date */
  public static LocalDateTime toLocalDateTime(Date date) {
    if (date == null) {
      return null;
    }
    return new DateTime(date).toInstant().atZone(DEFAULT_ZONE_OFF_SET).toLocalDateTime();
  }

  /** 毫秒转时间 */
  public static LocalDateTime toLocalDateTime(Long time) {
    if (time == null) {
      return null;
    }
    return new DateTime(time).toInstant().atZone(DEFAULT_ZONE_OFF_SET).toLocalDateTime();
  }

  public static LocalDateTime beginDateTimeOfMonth(LocalDateTime dateTime) {
    return LocalDate.of(dateTime.getYear(), dateTime.getMonthValue(), 1).atStartOfDay();
  }

  public static LocalDateTime beginOfDay(LocalDateTime dateTime) {
    return LocalDateTimeUtil.beginOfDay(dateTime);
  }

  public static Tuple2<LocalDateTime, LocalDateTime> beginAndEndOfMonth(LocalDateTime dateTime) {
    return Tuples.of(beginDateTimeOfMonth(dateTime), endDateTimeOfMonth(dateTime));
  }

  /** 获取当月最后一天 */
  public static LocalDate endDateOfMonth(Date date) {
    return endDateOfMonth(toLocalDate(date));
  }

  /** 获取当月最后一天 */
  public static LocalDate endDateOfMonth(LocalDate localDate) {
    return localDate.withDayOfMonth(getLengthOfMonth(localDate));
  }

  /** 获取当月最后一天 */
  public static LocalDateTime endDateTimeOfMonth(Date date) {
    return endDateTimeOfMonth(toLocalDateTime(date));
  }

  /** 获取当月最后一天 */
  public static LocalDateTime endDateTimeOfMonth(LocalDateTime localDateTime) {
    return end(localDateTime.withDayOfMonth(getLengthOfMonth(localDateTime)));
  }

  /** 获取当月天数 */
  public static int getLengthOfMonth(Date localDateTime) {
    return getLengthOfMonth(toLocalDate(localDateTime));
  }

  /** 获取当月天数 */
  public static int getLengthOfMonth(LocalDate localDateTime) {
    return localDateTime.lengthOfMonth();
  }

  /** 获取当月天数 */
  public static int getLengthOfMonth(LocalDateTime localDateTime) {
    return getLengthOfMonth(localDateTime.toLocalDate());
  }

  /** 获取年 */
  public static int getYear() {
    return thisYear();
  }

  public static String thisYearStr() {
    return String.valueOf(thisYear());
  }

  public static String getYearStr(int year) {
    return String.valueOf(getYear(year));
  }

  public static int getYear(int year) {
    return LocalDateTime.now().plusYears(year).getYear();
  }

  public static int lastYear() {
    return getYear(-1);
  }

  public static String lastYearStr() {
    return String.valueOf(getYear(-1));
  }

  public static LocalDateTime getTodayStart() {
    return LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
  }

  public static LocalDateTime getTodayEnd() {
    return LocalDateTime.now()
        .plusDays(1)
        .withHour(0)
        .withMinute(0)
        .withSecond(0)
        .withNano(0)
        .plusNanos(-1000L);
  }

  public static LocalDateTime begin(LocalDateTime localDateTime) {
    return Objects.requireNonNull(localDateTime)
        .withHour(0)
        .withMinute(0)
        .withSecond(0)
        .withNano(0);
  }

  public static Date begin(Date date) {
    return toDate(begin(toLocalDateTime(date)));
  }

  public static LocalTime begin(LocalTime localTime) {
    return Objects.requireNonNull(localTime).withHour(0).withMinute(0).withSecond(0).withNano(0);
  }

  public static LocalDateTime end(LocalDateTime localDateTime) {
    return Objects.requireNonNull(localDateTime)
        .plusDays(1)
        .withHour(0)
        .withMinute(0)
        .withSecond(0)
        .withNano(0)
        .plusNanos(-1000L);
  }

  public static Date getOffsetTimeOfMinutes(Date date, int minutes) {
    return toDate(toLocalDateTime(date).plusMinutes(minutes));
  }

  public static Date getOffsetTimeOfHours(Date date, int hours) {
    return toDate(toLocalDateTime(date).plusHours(hours));
  }

  public static Date getOffsetTimeOfDays(Date date, int days) {
    return toDate(toLocalDateTime(date).plusDays(days));
  }

  public static Date getOffsetTimeOfMonths(Date date, int months) {
    return toDate(toLocalDateTime(date).plusMonths(months));
  }

  public static Date getOffsetTimeOfYears(Date date, int years) {
    return toDate(toLocalDateTime(date).plusYears(years));
  }

  public static Date getOffsetTimeOfMinutes(int minutes) {
    return getOffsetTimeOfMinutes(new Date(), minutes);
  }

  public static Date getOffsetTimeOfHours(int hours) {
    return getOffsetTimeOfHours(new Date(), hours);
  }

  public static Date getOffsetTimeOfDays(int days) {
    return getOffsetTimeOfDays(new Date(), days);
  }

  public static Date getOffsetTimeOfMonths(int months) {
    return getOffsetTimeOfMonths(new Date(), months);
  }

  public static Date getOffsetTimeOfYear(int years) {
    return getOffsetTimeOfYears(new Date(), years);
  }

  /**
   * 返回一个DateTimeFormatter对象，该对象使用指定的日期时间格式和默认区域设置来格式化或解析日期时间。
   *
   * @param format 日期时间格式字符串，如 "yyyy-MM-dd HH:mm:ss"
   * @return 一个DateTimeFormatter对象，用于按照指定的日期时间格式和默认区域设置来格式化或解析日期时间
   */
  public static DateTimeFormatter formatter(String format) {
    return formatter(format, DEFAULT_LOCALE);
  }

  /**
   * 返回一个根据指定格式和区域设置创建的DateTimeFormatter对象。
   *
   * @param format 日期时间格式，如："yyyy-MM-dd HH:mm:ss"
   * @param locale 区域设置，用于解析和格式化日期时间的语言环境
   * @return 根据指定格式和区域设置创建的DateTimeFormatter对象
   * @throws IllegalArgumentException 如果格式字符串无效
   */
  public static DateTimeFormatter formatter(String format, Locale locale) {
    DATE_TIME_FORMATTER_CACHE.get(Tuples.of(format, locale));
    return DateTimeFormatter.ofPattern(format, locale);
  }

  private static String appendDoubleValue(int value) {
    return value >= 10 ? String.valueOf(value) : "0" + value;
  }

  /** 获取两位数，如果是1则会拼接01，如果是11则会拼接11 */
  private static void appendDoubleValue(StringBuilder sb, int value) {
    if (value >= 10) {
      sb.append(value);
    } else {
      sb.append("0").append(value);
    }
  }

  /**
   * 返回当前日期时间的字符串表示形式，按照指定的日期时间格式。
   *
   * @param format 日期时间格式，如："yyyy-MM-dd HH:mm:ss"
   * @return 当前日期时间的字符串表示形式
   */
  public static String nowStr(String format) {
    return FastDateFormat.getInstance(format).format(new Date());
  }

  /** 获取当前时间 yyyyMMddHHmmss */
  public static String nowStrDateTimeSimple() {
    var now = LocalDateTime.now();
    StringBuilder sb = new StringBuilder();
    appendDoubleValue(sb, now.getYear());
    appendDoubleValue(sb, now.getMonthValue());
    appendDoubleValue(sb, now.getDayOfMonth());
    appendDoubleValue(sb, now.getHour());
    appendDoubleValue(sb, now.getMinute());
    appendDoubleValue(sb, now.getSecond());
    return sb.toString();
  }

  /** 获取当前时间 yyMMddHHmmss */
  public static String nowStrDateTimeShort() {
    var now = LocalDateTime.now();
    StringBuilder sb = new StringBuilder();
    appendDoubleValue(sb, now.getYear() % 100);
    appendDoubleValue(sb, now.getMonthValue());
    appendDoubleValue(sb, now.getDayOfMonth());
    appendDoubleValue(sb, now.getHour());
    appendDoubleValue(sb, now.getMinute());
    appendDoubleValue(sb, now.getSecond());
    return sb.toString();
  }

  /** format yyyy-MM-dd HH:mm:ss */
  public static String nowStr() {
    return nowStr(DATETIME_FORMAT);
  }

  public static String nowDateStr() {
    return nowStr(DATE_FORMAT);
  }

  public static String nowDateStrSimple() {
    return nowStr(DATE_SIMPLE_FORMAT);
  }

  public static String nowTimeStr() {
    return nowStr(TIME_FORMAT);
  }

  public static Date parseDateTime(String str) {
    return parse(str, getDefaultFormats());
  }

  public static Date parseDateTime(String str, String format) {
    return parse(str, format);
  }

  public static Date parseDateTime(String str, String... formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return Dates.parse(str, formats);
  }

  public static LocalDate parseLocalDate(String str) {
    return parseLocalDate(str, getDefaultFormats());
  }

  public static LocalDate parseLocalDate(String str, String format) {
    return toLocalDate(Dates.parse(str, format));
  }

  public static LocalDate parseLocalDate(String str, String... formats) {
    if (StrUtil.isEmpty(str)) {
      return null;
    }
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }

    return toLocalDate(Dates.parse(str, formats));
  }

  public static LocalTime parseLocalTime(String str) {
    return toLocalTime(parse(str));
  }

  public static LocalTime parseLocalTime(String str, String format) {
    boolean isNext = false;
    if (format.equals("HH:mm") && "24:00".equals(str)) {
      str = "00:00";
      isNext = true;
    } else if (format.equals("HH:mm:ss") && "24:00:00".equals(str)) {
      str = "00:00:00";
      isNext = true;
    }
    LocalTime time = LocalTime.parse(str, formatter(format));
    if (isNext) {
      time = time.plusNanos(-1000);
    }
    return time;
  }

  public static LocalTime parseLocalTime(String str, String... formats) {
    if (StrUtil.isEmpty(str)) {
      return null;
    }
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }

    return toLocalTime(Dates.parse(str, formats));
  }

  public static LocalDateTime parseLocalDateTime(String str) {
    return toLocalDateTime(parse(str));
  }

  public static LocalDateTime parseLocalDateTime(String str, String format) {
    if (StrUtil.isEmpty(str)) {
      return null;
    }
    return LocalDateTimeUtil.parse(str, format);
  }

  public static LocalDateTime parseLocalDateTime(String str, String... formats) {
    if (StrUtil.isEmpty(str)) {
      return null;
    }
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return toLocalDateTime(Dates.parse(str, formats));
  }

  public static DateTime parse(String date) {
    return parse(date, getDefaultFormats());
  }

  public static DateTime parse(String date, String format) {
    return parse(date, new String[] {format});
  }

  /** 转换String为Date,支持多格式自动判断 */
  public static DateTime parse(String date, String... formats) {
    if (StrUtil.isEmpty(date)) {
      return null;
    }
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    try {
      return DateUtil.parse(date, formats);
    } catch (Exception e) {
      throw new ServiceException("不支持的日期格式:" + date);
    }
  }

  /** 对比String格式的时间 */
  public static <T extends Comparable<T>> int compare(
      String t1, String t2, String format, BiFunction<String, String, T> timeParser) {
    var dateTime1 = timeParser.apply(t1, format);
    var dateTime2 = timeParser.apply(t2, format);
    return dateTime1.compareTo(dateTime2);
  }

  public static <T extends Comparable<T>> int compare(
      String t1, String t2, String[] format, BiFunction<String, String[], T> timeParser) {
    var dateTime1 = timeParser.apply(t1, format);
    var dateTime2 = timeParser.apply(t2, format);
    return dateTime1.compareTo(dateTime2);
  }

  public static <T extends Comparable<T>> boolean isBetween(T time, T before, T after) {
    if (before.compareTo(after) > 0) {
      return false;
    }
    return time.compareTo(before) >= 0 && time.compareTo(after) <= 0;
  }

  public static <T extends Comparable<T>> boolean isBetween(
      String time,
      String before,
      String after,
      String format,
      BiFunction<String, String, T> timeParser) {
    var datetime = timeParser.apply(time, format);
    var beforeTime = timeParser.apply(before, format);
    var afterTime = timeParser.apply(after, format);
    return isBetween(datetime, beforeTime, afterTime);
  }

  public static boolean isNowBetween(LocalDateTime time1, LocalDateTime time2) {
    return isBetween(LocalDateTime.now(), time1, time2);
  }

  public static boolean isNowBetween(LocalDate time1, LocalDate time2) {
    return isBetween(LocalDate.now(), time1, time2);
  }

  public static boolean isNowBetween(LocalTime time1, LocalTime time2) {
    return isBetween(LocalTime.now(), time1, time2);
  }

  /** 和当前时间做对比 */
  public static <T extends Comparable<T>> int compareNow(
      String t1, String format, BiFunction<String, String, T> timeParser) {
    var dateTime1 = timeParser.apply(t1, format);
    var now = timeParser.apply(DateTime.now().toString(format), format);
    return dateTime1.compareTo(now);
  }

  public static <T extends Comparable<T>> int compareNow(
      String t1, String[] formats, BiFunction<String, String[], T> timeParser) {
    var dateTime1 = timeParser.apply(t1, formats);
    var now = timeParser.apply(DateTime.now().toString(formats[0]), formats);
    return dateTime1.compareTo(now);
  }

  public static <T extends Comparable<T>> boolean isAfter(
      String t1, String t2, String format, BiFunction<String, String, T> timeParser) {
    return compare(t1, t2, format, timeParser) > 0;
  }

  public static <T extends Comparable<T>> boolean isAfter(
      String t1, String t2, String[] format, BiFunction<String, String[], T> timeParser) {
    return compare(t1, t2, format, timeParser) > 0;
  }

  public static <T extends Comparable<T>> boolean isBefore(
      String t1, String t2, String format, BiFunction<String, String, T> timeParser) {
    return compare(t1, t2, format, timeParser) < 0;
  }

  public static <T extends Comparable<T>> boolean isBefore(
      String t1, String t2, String[] format, BiFunction<String, String[], T> timeParser) {
    return compare(t1, t2, format, timeParser) < 0;
  }

  public static <T extends Comparable<T>> boolean isAfterNow(
      String t1, String format, BiFunction<String, String, T> timeParser) {
    return compareNow(t1, format, timeParser) > 0;
  }

  public static <T extends Comparable<T>> boolean isAfterNow(
      String t1, String[] format, BiFunction<String, String[], T> timeParser) {
    return compareNow(t1, format, timeParser) > 0;
  }

  public static <T extends Comparable<T>> boolean isBeforeNow(
      String t1, String format, BiFunction<String, String, T> timeParser) {
    return compareNow(t1, format, timeParser) < 0;
  }

  public static <T extends Comparable<T>> boolean isBeforeNow(
      String t1, String[] format, BiFunction<String, String[], T> timeParser) {
    return compareNow(t1, format, timeParser) < 0;
  }

  public static int compareDateTime(String t1, String t2, String format) {
    return compare(t1, t2, format, Dates::parseDateTime);
  }

  public static int compareDateTime(String t1, String t2, String... formats) {
    return compare(t1, t2, formats, Dates::parseDateTime);
  }

  public static int compareLocalDate(String t1, String t2, String format) {
    return compare(t1, t2, format, Dates::parseLocalDate);
  }

  public static int compareLocalDate(String t1, String t2, String... formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return compare(t1, t2, formats, Dates::parseLocalDate);
  }

  public static int compareLocalTime(String t1, String t2, String format) {
    return compare(t1, t2, format, Dates::parseLocalTime);
  }

  public static int compareLocalTime(String t1, String t2, String... formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return compare(t1, t2, formats, Dates::parseLocalTime);
  }

  public static int compareLocalDateTime(String t1, String t2, String format) {
    return compare(t1, t2, format, Dates::parseLocalDateTime);
  }

  public static int compareLocalDateTime(String t1, String t2, String... formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return compare(t1, t2, formats, Dates::parseLocalDateTime);
  }

  public static int compareDateTimeNow(String t1, String format) {
    return compareNow(t1, format, Dates::parseDateTime);
  }

  public static int compareDateTimeNow(String t1, String... formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return compareNow(t1, formats, Dates::parseDateTime);
  }

  public static int compareLocalDateNow(String t1, String format) {
    return compareNow(t1, format, Dates::parseLocalDate);
  }

  public static int compareLocalDateNow(String t1, String[] formats) {
    return compareNow(t1, formats, Dates::parseLocalDate);
  }

  public static int compareLocalTimeNow(String t1, String format) {
    return compareNow(t1, format, Dates::parseLocalTime);
  }

  public static int compareLocalTimeNow(String t1, String[] formats) {
    return compareNow(t1, formats, Dates::parseLocalTime);
  }

  public static int compareLocalDateTimeNow(String t1, String format) {
    return compareNow(t1, format, Dates::parseLocalDateTime);
  }

  public static int compareLocalDateTimeNow(String t1, String[] formats) {
    if (ArrayUtil.isEmpty(formats)) {
      formats = getDefaultFormats();
    }
    return compareNow(t1, formats, Dates::parseLocalDateTime);
  }

  public static int compare(LocalDateTime time1, LocalDateTime time2) {
    return time1.compareTo(time2);
  }

  public static int compare(LocalDate time1, LocalDate time2) {
    return time1.compareTo(time2);
  }

  public static int compare(LocalTime time1, LocalTime time2) {
    return time1.compareTo(time2);
  }

  public static Date dateTime(Date date) {
    if (date == null) {
      return null;
    }
    if (date instanceof DateTime) {
      return (DateTime) date;
    }
    return new DateTime(date);
  }

  public static LocalDate toLocalDate(Date date) {
    if (date == null) {
      return null;
    }
    return new DateTime(date).toInstant().atZone(DEFAULT_ZONE_OFF_SET).toLocalDate();
  }

  public static LocalTime toLocalTime(Date date) {
    if (date == null) {
      return null;
    }
    return toLocalDateTime(date).toLocalTime();
  }

  public static int seconds(Date date) {
    return (int) (date.getTime() / (1000));
  }

  public static int seconds(LocalDateTime localDateTime) {
    return (int) (toEpochMilli(localDateTime) / (1000));
  }

  public static int diffDays(Date start, Date end) {
    return diffDays(toLocalDate(start), toLocalDate(end));
  }

  public static long diffDays(LocalDateTime start, LocalDateTime end) {
    // 转换Date到LocalDate
    LocalDate startDate = start.toLocalDate();
    LocalDate endDate = end.toLocalDate();
    return (int) ChronoUnit.DAYS.between(startDate, endDate);
  }

  public static int diffDays(LocalDate start, LocalDate end) {
    return (int) ChronoUnit.DAYS.between(start, end);
  }

  public static long diffHours(Date start, Date end) {
    return diffHours(toLocalDateTime(start), toLocalDateTime(end));
  }

  public static long diffHours(LocalDateTime start, LocalDateTime end) {
    return ChronoUnit.HOURS.between(start, end);
  }

  public static long diffMinutes(LocalDateTime start, LocalDateTime end) {
    return ChronoUnit.MINUTES.between(start, end);
  }

  public static long diffMinutes(Date start, Date end) {
    return diffMinutes(toLocalDateTime(start), toLocalDateTime(end));
  }

  public static long diffSeconds(LocalDateTime start, LocalDateTime end) {
    return ChronoUnit.SECONDS.between(start, end);
  }

  public static long diffSeconds(Date start, Date end) {
    return diffSeconds(toLocalDateTime(start), toLocalDateTime(end));
  }

  public static Date of(int year, int month, int day) {
    return toDate(LocalDate.of(year, month, day));
  }
}
